package com.dsl.dslallinone.core;

import com.dsl.dslallinone.common.exception.DslException;
import com.dsl.dslallinone.dto.DslQuery;
import com.dsl.dslallinone.common.config.MetricConfig;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 函数注册表
 */
@Component
public class FuncRegistry {
    private final Map<String, SqlFunction> functions = new HashMap<>();

    public FuncRegistry() {
        registerDefaultFunctions();
    }

    /**
     * 注册默认函数
     */
    private void registerDefaultFunctions() {
        // 基础聚合函数
        register("sum", new SumFunction());
        register("avg", new AvgFunction());
        register("max", new MaxFunction());
        register("min", new MinFunction());
        register("count", new CountFunction());
        register("distinct_count", new DistinctCountFunction());

        // 高级分析函数
        register("yoy", new YoyFunction());
        register("mom", new MomFunction());
        register("topN", new TopNFunction());
        register("pct_of_total", new PctOfTotalFunction());
        register("moving_avg", new MovingAvgFunction());
        register("rolling_sum", new RollingSumFunction());
        register("cumulative", new CumulativeFunction());
        register("growth_rate", new GrowthRateFunction());
        register("rank", new RankFunction());
    }

    /**
     * 注册函数
     */
    public void register(String name, SqlFunction function) {
        functions.put(name, function);
    }

    /**
     * 获取函数
     */
    public SqlFunction getFunction(String name) {
        SqlFunction function = functions.get(name);
        if (function == null) {
            throw new DslException("未知函数: " + name);
        }
        return function;
    }

    /**
     * SQL函数接口
     */
    public interface SqlFunction {
        String buildSql(MetricConfig metric, DslQuery query, String tableName);
    }

    /**
     * SUM函数
     */
    public static class SumFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("SUM(%s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * AVG函数
     */
    public static class AvgFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("AVG(%s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * MAX函数
     */
    public static class MaxFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("MAX(%s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * MIN函数
     */
    public static class MinFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("MIN(%s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * COUNT函数
     */
    public static class CountFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("COUNT(%s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * DISTINCT_COUNT函数
     */
    public static class DistinctCountFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("COUNT(DISTINCT %s) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * YOY同比函数
     */
    public static class YoyFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            String baseExpr = metric.getExpr().replaceAll("^(sum|avg|max|min)\\((.+)\\)$", "$2");
            return String.format(
                "(%s - LAG(%s, 1) OVER (PARTITION BY %s ORDER BY time_bucket)) / LAG(%s, 1) OVER (PARTITION BY %s ORDER BY time_bucket) * 100 AS %s",
                baseExpr, baseExpr, getPartitionFields(query), baseExpr, getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * MOM环比函数
     */
    public static class MomFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            String baseExpr = metric.getExpr().replaceAll("^(sum|avg|max|min)\\((.+)\\)$", "$2");
            return String.format(
                "(%s - LAG(%s, 1) OVER (PARTITION BY %s ORDER BY time_bucket)) / LAG(%s, 1) OVER (PARTITION BY %s ORDER BY time_bucket) * 100 AS %s",
                baseExpr, baseExpr, getPartitionFields(query), baseExpr, getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * TopN函数
     */
    public static class TopNFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("ROW_NUMBER() OVER (ORDER BY %s DESC) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * 占比函数
     */
    public static class PctOfTotalFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format(
                "%s / SUM(%s) OVER () * 100 AS %s",
                metric.getExpr(), metric.getExpr(), metric.getAs()
            );
        }
    }

    /**
     * 移动平均函数
     */
    public static class MovingAvgFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format(
                "AVG(%s) OVER (PARTITION BY %s ORDER BY time_bucket ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS %s",
                metric.getExpr(), getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * 滚动求和函数
     */
    public static class RollingSumFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format(
                "SUM(%s) OVER (PARTITION BY %s ORDER BY time_bucket ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS %s",
                metric.getExpr(), getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * 累计函数
     */
    public static class CumulativeFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format(
                "SUM(%s) OVER (PARTITION BY %s ORDER BY time_bucket) AS %s",
                metric.getExpr(), getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * 增长率函数
     */
    public static class GrowthRateFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format(
                "(%s - FIRST_VALUE(%s) OVER (PARTITION BY %s ORDER BY time_bucket)) / FIRST_VALUE(%s) OVER (PARTITION BY %s ORDER BY time_bucket) * 100 AS %s",
                metric.getExpr(), metric.getExpr(), getPartitionFields(query), metric.getExpr(), getPartitionFields(query), metric.getAs()
            );
        }
    }

    /**
     * 排名函数
     */
    public static class RankFunction implements SqlFunction {
        @Override
        public String buildSql(MetricConfig metric, DslQuery query, String tableName) {
            return String.format("RANK() OVER (ORDER BY %s DESC) AS %s", metric.getExpr(), metric.getAs());
        }
    }

    /**
     * 获取分区字段
     */
    private static String getPartitionFields(DslQuery query) {
        if (query.getGroupBy() != null && !query.getGroupBy().isEmpty()) {
            return String.join(", ", query.getGroupBy());
        }
        return "1"; // 默认分区
    }
}
